package com.ajavaer.framework.core.orm.service.impl;

import com.ajavaer.framework.core.orm.dao.BaseDAO;
import com.ajavaer.framework.core.orm.po.LogicDeletePo;
import com.ajavaer.framework.core.orm.service.LogicDeleteService;
import com.ajavaer.framework.core.request.PagingRequest;
import com.ajavaer.framework.core.request.RequestFilter;
import com.ajavaer.framework.core.request.RequestSpecification;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;

import java.io.Serializable;
import java.util.*;

public abstract class LogicDeleteServiceImpl<T extends LogicDeletePo, ID extends Serializable> implements LogicDeleteService<T, ID> {

    @Override
    public Page<T> findPaging(Integer page, Integer rows, Map<String, Object> searchParams, Sort sort) {
        Specification<T> spec = buildSpecification(searchParams);
        return findPaging(page, rows, spec, sort);
    }

    @Override
    public Page<T> findPaging(Integer page, Integer rows, Specification specification, Sort sort) {
        Specification requisite = requisite();
        if (specification != null) {
            requisite = requisite.and(specification);
        }
        return getBaseDAO().findAll(requisite, PageRequest.of(page - 1, rows, sort));
    }

    public Specification requisite() {
        Map<String, Object> searchParams = new HashMap<>();
        searchParams.put("EQ_del", false);
        return buildSpecification(searchParams);
    }

    @Override
    public Page<T> findPaging(PagingRequest request) {
        return findPaging(request.getPage(), request.getLimit(), request.getSearch(), request.sort());
    }

    @Override
    public List<T> findAll(Map<String, Object> searchParams) {
        return findAll(searchParams, null);
    }

    @Override
    public List<T> findAll(Map<String, Object> searchParams, Sort sort) {
        Specification<T> spec = buildSpecification(searchParams);
        return findAll(spec, sort);
    }

    @Override
    public List<T> findAll(Specification<T> spec, Sort sort) {
        Specification requisite = requisite();
        if (spec != null) {
            requisite = requisite.and(spec);
        }
        if (sort != null) {
            return getBaseDAO().findAll(requisite, sort);
        } else {
            return getBaseDAO().findAll(requisite);
        }
    }

    @Override
    public List<T> findAll() {
        return getBaseDAO().findAll(requisite());
    }

    @Override
    public List<T> findByProperty(String property, Object value, Sort sort) {
        Map<String, Object> searchParams = new HashMap<String, Object>();
        searchParams.put("EQ_del", false);
        searchParams.put(property, value);
        return findAll(searchParams, sort);
    }

    @Override
    public List<T> findByProperty(String property, Object value) {
        return findByProperty(property, value, null);
    }

    /**
     * 创建动态查询条件组合.
     */
    private Specification<T> buildSpecification(Map<String, Object> searchParams) {
        return new RequestSpecification<>(RequestFilter.parse(searchParams).values());
    }

    @Override
    public T getById(ID id) {
        if (id == null) {
            return null;
        }
        return getBaseDAO().getById(id);
    }

    @Override
    public T saveOrUpdate(T entity) {
        return getBaseDAO().saveAndFlush(entity);
    }

    @Override
    public void delete(T entity) {
        if (entity != null) {
            entity.setDel(true);
            saveOrUpdate(entity);
        }
    }

    @Override
    public void delete(ID id) {
        T entity = getById(id);
        delete(entity);
    }

    @Override
    public void delete(Iterable<T> entites) {
        if (entites != null) {
            Set<ID> ids = new HashSet<>();
            for (T entite : entites) {
                ids.add((ID) entite.getId());
            }
            if (ids.isEmpty()) {
                return;
            }
            List<T> entities = getBaseDAO().findByIdIn(ids);
            delete(entities);
        }
    }

    @Override
    public boolean exists(Example<T> entity) {
        return getBaseDAO().exists(entity);
    }


    @Override
    public void deleteByIdIn(Collection<ID> idList) {
        List<T> dbList = getBaseDAO().findAllById(idList);
        getBaseDAO().deleteInBatch(dbList);
    }

    public abstract BaseDAO<T, ID> getBaseDAO();

}